Note: Enterprise Objects Framework doesn't support modifiable primary key values-you shouldn't design your application so that users can change a primary key's value. If you really need this behavior, you have to implement it by deleting an affected object and reinserting it with a new primary key.
This is the technique used when your primary keys are integers. However, as described in the preceding section, when you want Enterprise Objects Framework to generate primary keys, you can also use 12 byte NSDatas. The difference is that integer primary keys are fetched from the database, whereas NSData keys are generated on the client (see the EOTemporaryGlobalID class specification in the Enterprise Objects Framework Reference for more information). Consequently, using 12 byte NSDatas is faster, but integer primary keys have the advantage of being more readable.
The following sections provide more information on when and how to use each mechanism.
To specify that an enterprise object provides its own key, you must set the primary key attributes as class properties in the object's entity. Your enterprise object class should provide an instance variable or accessor methods for each of the primary key attributes. If you want to provide the primary key value for a newly created enterprise object, be sure to assign it before the object is saved.
Note: In the case of Number objects (NSNumbers in Objective-C), don't set the value to zero unless you intend to have the primary key generated. See the section "Why is EOF Generating Primary Key Values for Number Objects Set to Zero?" below for details.)
On the other hand, if your application's user interface provides a way for the user to enter primary key values, you don't need to handle them any differently than you handle the object's other properties. For example, if an application uses social security numbers as the primary keys for employees, it must provide a way for users to enter them. The interface layer of the Framework takes care of assigning the user-provided value to the object.
The disadvantage of letting users enter primary key values is that there's a chance for data-entry error and the possibility that the object's primary key will need to be modified later. Since Enterprise Objects Framework doesn't support modifiable primary keys, you have to delete an object and reinsert it with a new primary key value to change its primary key. It's generally better to define a "meaningless" primary key to use instead.
To allow your EODatabaseContext's delegate to provide primary keys, implement the method databaseContextNewPrimaryKey (databaseContext:newPrimaryKeyForObject:entity: in Objective-C). An EODatabaseContext sends this method to its delegate when a newly inserted enterprise object doesn't have a primary key value. If the delegate is not implemented or returns null (nil), the EODatabaseContext gets a primary key by invoking a stored procedure or using its adaptor's database-specific mechanism.
To use a stored procedure to provide primary key values, you must define the stored procedure in your model. Stored procedures are read from the database when you create a new model and included in the model's .eomodeld file. You can also add stored procedures in EOModeler using the Stored Procedure view of the Model Editor.
After defining the stored procedure, you assign it to an entity. You can set it in EOModeler: In the Stored Procedure Inspector, type the name of the stored procedure in the Get PK field. Alternatively, you can set it programmatically using EOEntity's setStoredProcedure method (setStoredProcedure:forOperation: in Objective-C). For more information on defining stored procedures and assigning them to entities, see the section "How Do I Invoke a Stored Procedure?".
Each adaptor provides an implementation of the method primaryKeyForNewRowWithEntity (primaryKeyForNewRowWithEntity: in Objective-C). When invoked, this method returns a unique primary key value. For example, the Oracle adaptor uses Oracle sequences to generate unique values.
To use the adaptor's database-specific mechanism, you must be sure that your database accommodates the adaptor's scheme. The primary keys of the affected tables must be simple (that is, they can't be compound primary keys), and they must be number types.
To modify your database so that it supports the adaptor's mechanism for generating primary keys:
The Informix and Sybase adaptor use the same approach to generating primary key values. Both adaptors use a table named eo_sequence_table to keep track of the next available primary key value for a given table. The table contains a row for each table for which the adaptor provides primary key values.
The statements used to create the eo_sequence_tables are:
Informix | Sybase |
---|---|
create table eo_sequence_table (table_name varchar(32, 0), counter integer) |
create table eo_sequence_table (table_name varchar(32), counter int null) |
The adaptors use a stored procedure called eo_pk_for_table to access and maintain the primary key counters in eo_sequence_table. The stored procedures are defined as follows:
The stored procedures increment the counter in the eo_sequence_table row for the specified table, select the counter value, and return it. The Informix and Sybase adaptor's primaryKeyForNewRowWithEntity methods execute the eo_pk_for_table stored procedure and return the stored procedure's return value.
The approach taken by the ODBC adaptor is very similar to that of the Informix and Sybase adaptors. The ODBC adaptor uses a table named EO_PK_TABLE to keep track of the next available primary key value for a table, but the ODBC adaptor can create this table on demand. (The Informix and Sybase adaptors do not create the table and corresponding stored procedures. Rather, you create them ahead of time using the SQL Generation panel in EOModeler.)
The ODBC adaptor's primaryKeyForNewRowWithEntity method attempts to select a value from the EO_PK_TABLE for the new row's table. If the attempt fails because the table doesn't exist, the adaptor creates the table using the following SQL statement:
CREATE TABLE EO_PK_TABLE ( NAME TEXT_TYPE(40), PK NUMBER_TYPE )where TEXT_TYPE is the external (database) type for characters and NUMBER_TYPE is the external type for the table's primary key attribute. The ODBC adaptor sets the PK value for each row to the corresponding table's maximum primary key value plus one. After determining a primary key value for the new row, the ODBC adaptor updates the counter in the corresponding row in EO_PK_TABLE.
The Oracle adaptor uses sequence objects to provide primary key values. It creates a sequence using the following SQL statement:
create sequence table_SEQwhere table is the name of a table for which the adaptor provides primary key values. The adaptor sets the sequence start value to the corresponding table's maximum primary key value plus one.
Suppose that a database application allowed you to insert a row without providing a primary key value. An identity column or database trigger could generate an identifying value for the row, but the corresponding application object wouldn't have the value. The application could attempt to fetch the object using the values provided by the user, but a query that doesn't specify a primary key value might return more than one row. As a result, the application can't guarantee that it will be able to associate the current object with a row in the database. For this reason, Enterprise Objects Framework requires that you assign a primary key value to an object before it's inserted in the database.
This can cause problems if you have an existing database containing rows that use zero as the primary key value. The EODatabaseContext will incorrectly assume that an object created from that row needs a new primary key. This behavior may result in invalid foreign key references in other tables of your database.
To alter this behavior, assign a delegate to the EODatabaseContext object and implement the databaseContextNewPrimaryKey delegate method (databaseContext:newPrimaryKeyForObject:entity: in Objective-C) to return a Number object of value zero if the primary key should remain zero (an NSNumber in Objective-C), otherwise return null (nil). Returning null will tell EOF to find another way to generate the primary key value as described above.
Table of Contents
Next Section